#include<stdio.h>
#include<iostream>
#include<unistd.h>
#include<vector>
#include<time.h>
#include<sys/types.h>
#include<sys/wait.h>


#include"taks.hpp"

#define processnum 10

std::vector<ptask> _task;

//描述管道
class channel
{
public:
	channel(int cmdfd,pid_t slaverid,std::string& processname)
		:_cmdfd(cmdfd),_slaverid(slaverid),_processname(processname)
	{}

public:
	int _cmdfd;  //发送任务的文件描述符
  	pid_t _slaverid; //子进程的pid
	std::string _processname; //子进程的名字
};



//子进程的读取任务
void slaver()
{
	//子进程保证自己读取后还不退出，只有管道写端关闭后才会退出
	while(true)
	{
		//记录执行几号任务
		int taskid = 0;
		int n = read(0,&taskid,sizeof(int));
		if(n == sizeof(int))
		{
			std::cout << "slaver get commond@"<<getpid() << std::endl;
			if(taskid >=0 && taskid < _task.size())
				_task[taskid]();
			
			std::cout << std::endl;
		}
		//写端关闭退出循环
		else if(n == 0)
		{
			break;
		}
	}
}

//输出型参数用我们的*
void initPool(std::vector<channel>* channels)
{
	//记录父进程的写端
	std::vector<int> old;
	for(int i = 0;i < processnum;i++)
	{
		int pipefd[2];
		int n = pipe(pipefd);
		if(n != 0)
		{
			perror("pipe");
			exit(1);
		}
		pid_t id = fork();
		if(id < 0)
		{
			perror("fork");
			exit(1);
		}

		//子进程
		if(id == 0)
		{
			//删除之前父进程的写端，避免子进程继承父进程后，前面管道不能正常关闭
			for(auto e : old)
			{
				close(e);
			}
			//关闭写端
			close(pipefd[1]);
			//重定向标准输入到管道的读端
			dup2(pipefd[0],0);
			close(pipefd[0]);
			//子进程执行任务
			slaver();
            std::cout << "process : " << getpid() << " quit" << std::endl;
			exit(0);
		}
		//父进程
		close(pipefd[0]);
		old.push_back(pipefd[1]);
		//将子进程管理起来
		std::string name = "process-" + std::to_string(i);
		channels->push_back(channel(pipefd[1],id,name));
	}
}

void menu()
{
	std::cout << "###############################################" << std::endl;
    std::cout << "# 1. 刷新日志         2. 刷新出来野怪           #" << std::endl;
    std::cout << "# 3. 检测软件是否更新     4. 更新用的血量和蓝量  #" << std::endl;
    std::cout << "#                 0. 退出                     #" << std::endl;
    std::cout << "###############################################" << std::endl;
}



void controlSlavor(std::vector<channel>& channels)
{
	//srand(time(nullptr));//种下随机种子
	while(true)
	{
		//打印选项单
		menu();
		std::cout << "请选择任务：";
		int select;
		std::cin >> select;
		if(select == 0)
		{
			std::cout << "任务完成程序正在退出！！"<< std::endl;
			break;
		}
			
		else if(select < 0 || select > 4)
		{
			std::cout << "输入错误请重新输入"<<std::endl;
			continue;
		}
		
		int taskid = select-1;

		int which = 0;
		//父进程派发任务给子进程——即写入我们对应的管道，对应的子进程的那根管道就能读取任务id就根据id完成任务。
		std::cout << "father send the taskid, pid:"<<channels[which]._slaverid << " name: "<<channels[which]._processname << " should commit it!!!" << std::endl;
		write(channels[which]._cmdfd,&taskid,sizeof(int));
		sleep(1);
		//以循环调用子进程的方式
		which++;
		which %= channels.size();
	}
}


void quitProcess(std::vector<channel> channels)
{
	for(auto cha : channels)
	{
		close(cha._cmdfd);
		waitpid(cha._slaverid,nullptr,0);
	}
}


int main()
{
	//加载我们的任务列表
	load(&_task);

	//创建我们的子进程和管道。
	std::vector<channel> channels;
  	initPool(&channels);

	//控制子进程执行任务
	controlSlavor(channels);

	//清理我们的所以进程
	quitProcess(channels);

  	return 0;
}
